package com.CST.service.impl.ys;

import com.CST.bo.YsSubjectTypeBO;
import com.CST.common.BaseEntity;
import com.CST.common.api.ResultObject;
import com.CST.dto.ys.YsSubjectDTO;
import com.CST.entity.ys.*;
import com.CST.mapper.cst.ys.YsSubjectMapper;
import com.CST.service.ys.*;
import com.CST.util.ExcelTransfer;
import com.CST.vo.ys.DeptVO;
import com.CST.vo.ys.YsSubjectListVO;
import com.CST.vo.ys.YsSubjectVO;
import com.CST.vo.ys.YySubjectVO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author qtx
 * @since 2023-04-23
 */
@Service
public class YsSubjectServiceImpl extends ServiceImpl<YsSubjectMapper, YsSubject> implements YsSubjectService {

    private final YsSubjectDepartmentService ysSubjectDepartmentService;

    private final YsSubjectTypeService ysSubjectTypeService;

    private final YsBusinessSubjectService ysBusinessSubjectService;

    private final YsManageSubjectService ysManageSubjectService;

    private final YsDepartmentService ysDepartmentService;

    private final YsDictionaryService ysDictionaryService;

    private final ExcelTransfer<YsSubjectVO> excelTransfer;

    public YsSubjectServiceImpl(YsSubjectDepartmentService ysSubjectDepartmentService, YsSubjectTypeService ysSubjectTypeService, YsBusinessSubjectService ysBusinessSubjectService, YsManageSubjectService ysManageSubjectService, YsDepartmentService ysDepartmentService, YsDictionaryService ysDictionaryService, ExcelTransfer<YsSubjectVO> excelTransfer) {
        this.ysSubjectDepartmentService = ysSubjectDepartmentService;
        this.ysSubjectTypeService = ysSubjectTypeService;
        this.ysBusinessSubjectService = ysBusinessSubjectService;
        this.ysManageSubjectService = ysManageSubjectService;
        this.ysDepartmentService = ysDepartmentService;
        this.ysDictionaryService = ysDictionaryService;
        this.excelTransfer = excelTransfer;
    }

    @Override
    public IPage<YsSubjectVO> listYsSubjectPage(YsSubjectDTO dto) {
        boolean subjectCode = StringUtils.isNotBlank(dto.getSubjectCode());
        boolean subjectName = StringUtils.isNotBlank(dto.getSubjectName());
        IPage<YsSubjectVO> ysSubjectVOS;
        if (!(subjectCode || subjectName)) {
            ysSubjectVOS = baseMapper.selectPageParent(dto.getPage(),
                    Wrappers.lambdaQuery(YsSubject.class)
                            .eq(BaseEntity::getDeleteFlag, Boolean.FALSE)
                            .eq(YsSubject::getParent, 0));
            List<YsSubjectVO> records = ysSubjectVOS.getRecords();
            List<YsSubjectVO> child = baseMapper.selectChild(Wrappers.lambdaQuery(YsSubject.class)
                    .eq(BaseEntity::getDeleteFlag, Boolean.FALSE)
                    .ne(YsSubject::getParent, 0)
                    .in(YsSubject::getFirstId, records
                            .stream()
                            .map(YsSubjectVO::getId)
                            .collect(Collectors.toList())));
            records.forEach(v -> v.setChildList(getChildVO(v, child)));
        } else {
            ysSubjectVOS = baseMapper.selectItem(dto.getPage(),
                    Wrappers.lambdaQuery(YsSubject.class)
                            .eq(BaseEntity::getDeleteFlag,
                                    Boolean.FALSE)
                            .like(subjectCode,YsSubject::getSubjectCode,
                                    dto.getSubjectCode())
                            .like(subjectName,YsSubject::getSubjectName,
                                    dto.getSubjectName()));
            ysSubjectVOS.getRecords().forEach(this::setField);
        }
        return ysSubjectVOS;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveOrUpdateYsSubject(YsSubject entity) {
        Optional.ofNullable(entity.getSubjectCode())
                .orElseThrow(() -> new RuntimeException("预算编号为空。"));
        YsSubject one = getOne(Wrappers.lambdaQuery(YsSubject.class)
                .eq(BaseEntity::getDeleteFlag, Boolean.FALSE)
                .eq(YsSubject::getSubjectCode, entity.getSubjectCode())
                .ne(entity.getId() != null, BaseEntity::getId, entity.getId()));

        // 编辑的时候取消业务职能或者管理职能的时候去删除相应的对照关系
        if (entity.getId() != null){
            // 判断编辑的时候是否修改了类型
            List<Long> typeList = baseMapper.selectTypeList(entity.getId());
            typeList.removeAll(entity.getType());
            for (Long t : typeList){
                if (t == 5 && entity.getId() != null) {
                    // 删除业务职能对照关系,只删除当前年的
                    baseMapper.updateDeleteFlag("ys_business_subject",entity.getId(), Calendar.getInstance().get(Calendar.YEAR));
                }
                if (t == 6) {
                    // 删除管理职能对照关系
                    baseMapper.updateDeleteFlag("ys_manage_subject",entity.getId(),Calendar.getInstance().get(Calendar.YEAR));
                }
            }
        }

        if (Objects.isNull(one)) {
            boolean saveOrUpdate = saveOrUpdate(entity);
            Long id = entity.getId();
            //updateBusinessAndManage(entity);
            removeTypeAndDepartment(Collections.singletonList(entity.getId()));
            List<Long> type = entity.getType();
            List<Long> departments = entity.getDepartments();
            if (type != null && !type.isEmpty()) {
                ysDepartmentService.update(Wrappers.lambdaUpdate(YsDepartment.class)
                        .setSql("num = num+1")
                        .in(BaseEntity::getId, type));
                type.forEach(e -> ysSubjectTypeService.save(YsSubjectType.builder()
                        .typeId(e)
                        .subjectId(id)
                        .build()));
            }
            if (departments != null && !departments.isEmpty()) {
                ysDepartmentService.update(Wrappers.lambdaUpdate(YsDepartment.class)
                        .setSql("num = num+1")
                        .in(BaseEntity::getId, departments));
                departments.forEach(e -> ysSubjectDepartmentService.save(YsSubjectDepartment.builder()
                        .departmentId(e)
                        .subjectId(id)
                        .build()));
            }
            return saveOrUpdate;
        } else {
            throw new RuntimeException("预算编码重复。");
        }
    }

    @Override
    public List<YsSubjectVO> listYsSubjectTree() {
        List<YsSubjectVO> list = baseMapper.selectAll();
        return list.stream()
                .filter(f -> f.getParent()
                        .equals(0))
                .peek(p -> p.setChildList(getChildVO(p, list)))
                .collect(Collectors.toList());
    }

    @Override
    public List<YsSubjectListVO> listYsSubject() {
        return baseMapper.selectChildList();
    }

    @Override
    public List<YsSubjectListVO> listYsSubject1(String name) {
        return baseMapper.selectByCode(name, Arrays.asList("31003", "31004"));
    }

    @Override
    public List<YsSubjectListVO> listYsSubject2(String name) {
        return baseMapper.selectByCode(name, Collections.singletonList("31002"));
    }

    @Override
    public List<YsSubjectListVO> listYsSubject3(String name) {
        return baseMapper.selectByCode(name, Collections.singletonList("31001"));
    }

    @Override
    public List<YsSubjectListVO> listYsSubject4(String name) {
        return baseMapper.selectByType(name, "业务职能");
    }

    @Override
    public List<YsSubjectListVO> listYsSubject5(String name) {
        return baseMapper.selectByType(name, "管理职能");
    }

    @Override
    public List<YySubjectVO> listYySubject(String year, String name) {
        return baseMapper.selectYySubject(year, name);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeYsSubjectById(Long id) {
        List<YsSubject> list = list(Wrappers.lambdaQuery(YsSubject.class)
                .eq(BaseEntity::getDeleteFlag, Boolean.FALSE));
        List<YsSubject> ysSubjects = new ArrayList<>();
        List<YsSubject> collect = list.stream()
                .filter(f -> f.getId()
                        .equals(id))
                .collect(Collectors.toList());
        if (collect.size() == 1) {
            getChild(collect.get(0), list, ysSubjects);
        }
        List<Long> idList = ysSubjects.stream()
                .map(BaseEntity::getId)
                .collect(Collectors.toList());
        idList.add(id);
        boolean removedByIds = removeByIds(idList);
        removeTypeAndDepartment(idList);
        ysBusinessSubjectService.update(Wrappers.lambdaUpdate(YsBusinessSubject.class)
                .set(BaseEntity::getDeleteFlag, Boolean.TRUE)
                .in(YsBusinessSubject::getSubjectId, idList));
        ysManageSubjectService.update(Wrappers.lambdaUpdate(YsManageSubject.class)
                .set(BaseEntity::getDeleteFlag, Boolean.TRUE)
                .in(YsManageSubject::getSubjectId, idList));
        return removedByIds;
    }

    private void removeTypeAndDepartment(List<Long> idList) {
        List<YsSubjectDepartment> departmentList = ysSubjectDepartmentService.list(
                Wrappers.lambdaQuery(YsSubjectDepartment.class)
                        .eq(BaseEntity::getDeleteFlag, Boolean.FALSE)
                        .in(YsSubjectDepartment::getSubjectId, idList));
        List<YsSubjectType> ysSubjectTypes = ysSubjectTypeService.list(Wrappers.lambdaQuery(YsSubjectType.class)
                .eq(BaseEntity::getDeleteFlag, Boolean.FALSE)
                .in(YsSubjectType::getSubjectId, idList));
        List<Long> departmentIdList = departmentList.stream()
                .map(YsSubjectDepartment::getDepartmentId)
                .collect(Collectors.toList());
        if (!departmentIdList.isEmpty()) {
            ysDepartmentService.update(Wrappers.lambdaUpdate(YsDepartment.class)
                    .setSql("num = num-1")
                    .in(BaseEntity::getId, departmentIdList));
        }
        List<Long> typeIdList = ysSubjectTypes.stream()
                .map(YsSubjectType::getTypeId)
                .collect(Collectors.toList());
        if (!typeIdList.isEmpty()) {
            ysDepartmentService.update(Wrappers.lambdaUpdate(YsDepartment.class)
                    .setSql("num = num-1")
                    .in(BaseEntity::getId, typeIdList));
        }
        ysSubjectDepartmentService.update(Wrappers.lambdaUpdate(YsSubjectDepartment.class)
                .set(BaseEntity::getDeleteFlag, Boolean.TRUE)
                .in(YsSubjectDepartment::getSubjectId, idList));
        ysSubjectTypeService.update(Wrappers.lambdaUpdate(YsSubjectType.class)
                .set(BaseEntity::getDeleteFlag, Boolean.TRUE)
                .in(YsSubjectType::getSubjectId, idList));
    }

    @Override
    public void importExcelYsSubject(MultipartFile file) {
        excelTransfer.importExcel(file, null, YsSubjectVO.class, list -> {
            list.forEach(e -> {

            });
            return new ArrayList<>();
        });
    }

    @Override
    public void exportExcelYsSubject(HttpServletResponse response) {
        YsSubjectDTO dto = new YsSubjectDTO();
        dto.setNum(1);
        dto.setSize(Integer.MAX_VALUE);
        List<YsSubjectVO> records = listYsSubjectPage(dto).getRecords();
        List<YsSubjectVO> list = new ArrayList<>();
        records.forEach(e -> addList(e, list));
        excelTransfer.exportExcel(response, list, "预算科目", "sheet",
                YsSubjectVO.class);
    }

    public void addList(YsSubjectVO e, List<YsSubjectVO> list) {
        list.add(e);
        Optional.ofNullable(e.getChildList())
                .orElse(new ArrayList<>())
                .forEach(v -> addList(v, list));
    }

    @Override
    public void exportExcelYsSubjectDemo(HttpServletResponse response) {
        excelTransfer.exportExcel(response, new ArrayList<>(), "预算科目模板", "sheet", YsSubjectVO.class);
    }

    @Override
    public List<DeptVO> listManageDept(Long subjectId) {
        List<DeptVO> list = baseMapper.selectManageDeptById(subjectId);
        return list;
    }

    @Override
    public ResultObject getExistingRelationship(YsSubject entity) {
        if (entity.getId() != null){
            // 根据id查询修改前有几个职能类型
            List<Long> typeList = baseMapper.selectTypeList(entity.getId());
            // 判断原本的type与这次编辑后的type的区别
            typeList.removeAll(entity.getType());
            // 根据id查询之前存在的业务对照关系
            Integer businessCount = baseMapper.selectBusinessCount(entity.getId());
            Integer manageCount = baseMapper.selectManageCount(entity.getId());
            for (Long type : typeList){
                if (type == 5 && businessCount >0){
                    return ResultObject.errorReturn("取消的业务职能仍然存在业务职能科目对照关系，是否确定取消业务职能");
                }
                if (type == 6 && manageCount > 0){
                    return ResultObject.errorReturn("取消的管理职能仍然存在管理职能科目对照关系，是否确定取消管理职能");
                }
            }
        }
        return ResultObject.successReturn("成功");
    }

    private List<YsSubject> getChild(YsSubject p, List<YsSubject> list, List<YsSubject> ysSubjects) {
        return list.stream()
                .filter(f -> f.getParent() != null && f.getParent()
                        .equals(p.getId()))
                .peek(ysSubjects::add)
                .peek(ppp -> ppp.setChildList(getChild(ppp, list, ysSubjects)))
                .collect(Collectors.toList());
    }

    private List<YsSubjectVO> getChildVO(YsSubjectVO y, List<YsSubjectVO> list) {
        List<YsSubjectVO> collect = list.stream()
                .filter(f -> f.getParent() != null && f.getParent()
                        .equals(y.getId()))
                .peek(this::setField)
                .peek(p -> p.setChildList(getChildVO(p, list)))
                .collect(Collectors.toList());
        if (collect.isEmpty()) {
            return null;
        }
        return collect;
    }

    private void setField(YsSubjectVO vo) {
        StringBuilder names = new StringBuilder();
        StringBuilder codes = new StringBuilder();
        List<Long> deptIds = new ArrayList<>();
        List<YsDepartment> departments =
                Optional.ofNullable(vo.getDepartments())
                        .orElse(new ArrayList<>());
        if (!departments.isEmpty()) {
            for (int i = 0; ; i++) {
                YsDepartment ysDepartment = departments.get(i);
                codes.append(ysDepartment.getDepartmentCode());
                names.append(ysDepartment.getDepartmentName());
                deptIds.add(ysDepartment.getId());
                if (i == departments.size() - 1) {
                    break;
                }
                names.append(", ");
                codes.append(", ");
            }
        }
        vo.setDepartmentNames(names.toString());
        vo.setDepartmentCodes(codes.toString());
        vo.setDeptIds(deptIds);

        List<YsSubjectTypeBO> boList = Optional.ofNullable(vo.getTypes())
                .orElse(new ArrayList<>());
        if (boList.isEmpty()) {
            return;
        }
        StringBuilder types = new StringBuilder();
        List<Long> typeIds = new ArrayList<>();
        for (int i = 0; ; i++) {
            YsSubjectTypeBO bo = boList.get(i);
            types.append(bo.getName());
            typeIds.add(bo.getId());
            if (i == boList.size() - 1) {
                break;
            }
            types.append("、");
        }
        vo.setType(types.toString());
        vo.setTypeIds(typeIds);
    }

/*    public void updateBusinessAndManage(YsSubject entity) {
        Long id = entity.getId();
        List<YsDictionary> types = ysDictionaryService.listYsDictionary("type", null);
        Map<Long, String> collect = types.stream()
                .collect(Collectors.toMap(BaseEntity::getId, YsDictionary::getDictionaryName));
        List<Long> list = Optional.ofNullable(entity.getType())
                .orElse(new ArrayList<>());
        StringBuilder stringBuilder = new StringBuilder();
        if (list.size() > 0) {
            for (int i = 0; ; i++) {
                stringBuilder.append(collect.get(list.get(i)));
                if (list.size() - 1 == i) {
                    break;
                }
                stringBuilder.append("、");
            }
        }
        switch (stringBuilder.toString()) {
            case "业务职能":
                removeYsManage(id);
                ysBusiness(id);
                removeYsBusiness(id);
                break;
            case "管理职能":
                removeYsBusiness(id);
                ysManage(id);
                removeYsManage(id);
                break;
            case "管理职能、业务职能":
            case "业务职能、管理职能":
                ysBusiness(id);
                ysManage(id);
                break;
            default:
        }
    }

    private void ysManage(Long id) {
        YsManageSubject ysManageSubjectServiceOne = ysManageSubjectService.getOne(
                Wrappers.lambdaUpdate(YsManageSubject.class)
                        .eq(YsManageSubject::getSubjectId, id));
        YsManageSubject ysManageSubject = Optional.ofNullable(ysManageSubjectServiceOne)
                .orElse(new YsManageSubject());
        ysManageSubject.setSubjectId(id);
        ysManageSubjectService.save(ysManageSubject);
    }

    private void removeYsManage(Long id) {
        ysManageSubjectService.update(Wrappers.lambdaUpdate(YsManageSubject.class)
                .set(BaseEntity::getDeleteFlag, Boolean.TRUE)
                .eq(YsManageSubject::getSubjectId, id));
    }

    private void ysBusiness(Long id) {
        YsBusinessSubject ysBusinessSubjectServiceOne = ysBusinessSubjectService.getOne(
                Wrappers.lambdaUpdate(YsBusinessSubject.class)
                        .eq(YsBusinessSubject::getSubjectId, id));
        YsBusinessSubject ysBusinessSubject = Optional.ofNullable(ysBusinessSubjectServiceOne)
                .orElse(new YsBusinessSubject());
        ysBusinessSubject.setSubjectId(id);
        ysBusinessSubjectService.save(ysBusinessSubject);
    }

    private void removeYsBusiness(Long id) {
        ysBusinessSubjectService.update(Wrappers.lambdaUpdate(YsBusinessSubject.class)
                .set(BaseEntity::getDeleteFlag, Boolean.TRUE)
                .eq(YsBusinessSubject::getSubjectId, id));
    }*/
}
